package com.ethink.platform.controller.warehouse;

import cn.hutool.core.util.IdUtil;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.db.KeyValueDTO;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.framework.common.web.BaseController;
import com.ethink.framework.common.web.context.SPRequestContextHolder;
import com.ethink.framework.common.web.response.CommonResponse;
import com.ethink.order.api.*;
import com.ethink.order.api.model.LogisticsTraceOrderRkConfirmDetailExcelImportModel;
import com.ethink.order.api.model.PurchaseOrderNoAndQtyModel;
import com.ethink.platform.controller.order.info.ExportInfo;
import com.ethink.platform.manager.ExportManager;
import com.ethink.platform.manager.LogisticsTraceOrderManager;
import com.ethink.report.api.info.TobSaleInfo;
import com.ethink.report.common.mapper.MateInventoryOrderQueryMapper;
import com.ethink.system.api.SystemFileFacade;
import com.ethink.system.api.info.SystemFileInfo;
import com.ethink.warehouse.api.LogisticsTraceApplyOrderFacade;
import com.ethink.warehouse.api.LogisticsTraceOrderFacade;
import com.ethink.warehouse.api.LogisticsTransferOrderFacade;
import com.ethink.warehouse.api.enums.InventoryTypeEnum;
import com.ethink.warehouse.api.enums.SubjectEnum;
import com.ethink.warehouse.api.info.LogisticsStepInfo;
import com.ethink.warehouse.api.info.LogisticsTraceOrderInfo;
import com.ethink.warehouse.api.request.*;
import com.ethink.warehouse.api.response.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 物流跟进单 Controller
 *
 * @author default
 * @date 2022-11-10
 */
@Tag(name = "LogisticsTraceOrderController", description = "物流跟进单 Controller")
@RestController
@Slf4j
@RequestMapping("platform-server/v1/warehouse-service")
public class LogisticsTraceOrderController extends BaseController {

    @Autowired
    private LogisticsTraceOrderFacade logisticsTraceOrderFacade;

    @Autowired
    private SystemFileFacade systemFileFacade;

    @Autowired
    private LogisticsTraceApplyOrderFacade logisticsTraceApplyOrderFacade;

    @Autowired
    private PurchaseReturnOrderFacade purchaseReturnOrderFacade;

    @Autowired
    private SaleOrderFacade saleOrderFacade;

    @Autowired
    private SaleReturnOrderFacade saleReturnOrderFacade;

    @Autowired
    private TobSaleOrderFacade tobSaleOrderFacade;

    @Autowired
    private TobSaleReturnOrderFacade tobSaleReturnOrderFacade;

    @Autowired
    private LogisticsTransferOrderFacade logisticsTransferOrderFacade;

    @Autowired
    private OrderServiceStatusFacade orderServiceStatusFacade;

    @Autowired
    private PurchaseOrderFacade purchaseOrderFacade;

    @Autowired
    private MateInventoryOrderQueryMapper mateInventoryOrderQueryMapper;

    @Autowired
    private LogisticsTraceOrderManager logisticsTraceOrderManager;

    @Autowired
    private ExportManager exportManager;

    @Operation(summary = "分页查询")
    @GetMapping("/logisticsTraceOrder/query")
    public CommonResponse<List<LogisticsTraceOrderQueryResponse>> queryLogisticsTraceOrder(LogisticsTraceOrderQueryRequest request) {
        return succeedWithPage(logisticsTraceOrderFacade.queryLogisticsTraceOrder(request));
    }

    @Operation(summary = "货品模式分页查询")
    @GetMapping("/logisticsTraceOrder/queryGoodsMode")
    public CommonResponse<List<LogisticsTraceOrderQueryGoodsModeResponse>> queryLogisticsTraceOrderGoodsMode(LogisticsTraceOrderQueryGoodsModeRequest request) {
        return succeedWithPage(logisticsTraceOrderFacade.queryLogisticsTraceOrderGoodsMode(request));
    }

    @Operation(summary = "物流跟进单货品模式导出Excel")
    @GetMapping("/logisticsTraceOrder/exportGoodsMode")
    public CommonResponse<ExportInfo> exportLogisticsTraceOrderGoodsMode(LogisticsTraceOrderQueryGoodsModeRequest request) {
        return succeedWith(exportManager.exportLogisticsTraceOrderGoodsMode(request));
    }

    @Operation(summary = "详情查询")
    @GetMapping("/logisticsTraceOrder/get/{logisticsTraceOrderId}")
    public CommonResponse<LogisticsTraceOrderGetDetailResponse> getLogisticsTraceOrderById(@PathVariable("logisticsTraceOrderId") Long logisticsTraceOrderId) {
        LogisticsTraceOrderGetDetailResponse response = logisticsTraceOrderFacade.getLogisticsTraceOrderById(logisticsTraceOrderId);

        List<String> fileIdList = new ArrayList<>();
        LogisticsTraceOrderInfo traceOrderInfo = response.getLogisticsTraceOrderInfo();
        //!null处理
        Optional<LogisticsTraceOrderInfo> traceOrder = Optional.ofNullable(traceOrderInfo);
        traceOrder.ifPresent(a -> {
            if (a.getPackageFileId() != null) {
                fileIdList.add(a.getPackageFileId());
            }
            if (a.getConfirmFileId() != null) {
                fileIdList.add(a.getConfirmFileId());
            }
        });
        if (fileIdList.size() > 0) {
            Map<String, SystemFileInfo> fileInfoMap = systemFileFacade.selectMapByFileIds(fileIdList);
            if (traceOrderInfo.getPackageFileId() != null) {
                traceOrderInfo.setPackageFileUrl(fileInfoMap.get(traceOrderInfo.getPackageFileId()).getUrl());
            }
            if (traceOrderInfo.getConfirmFileId() != null) {
                traceOrderInfo.setConfirmFileUrl(fileInfoMap.get(traceOrderInfo.getConfirmFileId()).getUrl());
            }
        }

        return succeedWith(response);
    }

    @Operation(summary = "待确认明细列表")
    @GetMapping("/logisticsTraceOrder/listRkConfirmDetail/{logisticsTraceOrderId}")
    public CommonResponse<List<LogisticsTraceOrderListRkConfirmDetailResponse>> listLogisticsTraceOrderRkConfirmDetail(@PathVariable("logisticsTraceOrderId") Long logisticsTraceOrderId) {
        List<LogisticsTraceOrderListRkConfirmDetailResponse> list = logisticsTraceOrderFacade.listLogisticsTraceOrderRkConfirmDetail(logisticsTraceOrderId);
        if (CollectionUtils.isNotEmpty(list)) {
            if (SubjectEnum.T41.getCode().equals(list.get(0).getSourceOrderType())) {
                list = t42List(list);
            } else if (SubjectEnum.T71.getCode().equals(list.get(0).getSourceOrderType())) {
                list = t72List(list);
            }
        }
        return succeedWith(list);
    }

    @Operation(summary = "待确认明细列表导出Excel")
    @GetMapping("/logisticsTraceOrder/exportRkConfirmDetail/{logisticsTraceOrderId}")
    public CommonResponse<ExportInfo> exportLogisticsTraceOrderRkConfirmDetail(@PathVariable("logisticsTraceOrderId") Long logisticsTraceOrderId) {
        return succeedWith(exportManager.exportLogisticsTraceOrderRkConfirmDetail(logisticsTraceOrderId));
    }

    @Operation(summary = "待确认明细列表Excel导入")
    @PostMapping("/logisticsTraceOrder/importRkConfirmDetail/{logisticsTraceOrderId}")
    public CommonResponse<List<LogisticsTraceOrderListRkConfirmDetailResponse>> importLogisticsTraceOrderRkConfirmDetail(
            @PathVariable("logisticsTraceOrderId") Long logisticsTraceOrderId,
            @RequestParam("file") MultipartFile file
    ) {
        return succeedWith(logisticsTraceOrderManager.excelImport(logisticsTraceOrderId, file));
    }

    private List<LogisticsTraceOrderListRkConfirmDetailResponse> t42List(List<LogisticsTraceOrderListRkConfirmDetailResponse> responseList) {
        List<String> mateSkuList = responseList.stream().map(LogisticsTraceOrderListRkConfirmDetailResponse::getMateSku)
                .distinct()
                .collect(Collectors.toList());
        List<String> returnOrderNoList = responseList.stream().map(LogisticsTraceOrderListRkConfirmDetailResponse::getSourceOrderNo)
                .distinct()
                .collect(Collectors.toList());
        List<KeyValueDTO> returnOrderList = mateInventoryOrderQueryMapper.queryT42OrderNo(returnOrderNoList);
        Map<String, String> returnOrderNoMap = returnOrderList.stream()
                .collect(Collectors.toMap(KeyValueDTO::getStringKey, KeyValueDTO::getStringValue));

        List<TobSaleInfo> tobSaleInfoList = mateInventoryOrderQueryMapper.queryT42(returnOrderNoList);
        tobSaleInfoList = tobSaleInfoList.stream()
                .filter(info -> mateSkuList.contains(info.getMateSku())).collect(Collectors.toList());
        List<LogisticsTraceOrderListRkConfirmDetailResponse> newList = new ArrayList<>();

        for (LogisticsTraceOrderListRkConfirmDetailResponse item : responseList) {
            String saleOrderNo = returnOrderNoMap.get(item.getSourceOrderNo());
            String mateSku = item.getMateSku();
            String mergeKey = IdUtil.fastSimpleUUID();
            for (TobSaleInfo tobSaleInfo : tobSaleInfoList) {
                if (tobSaleInfo.getSaleOrderNo().equals(saleOrderNo) && tobSaleInfo.getMateSku().equals(mateSku)) {
                    LogisticsTraceOrderListRkConfirmDetailResponse newItem = new LogisticsTraceOrderListRkConfirmDetailResponse();
                    BeanUtils.copyProperties(item, newItem);
                    newItem.setInventoryType(InventoryTypeEnum.ZP.getIntValue());
                    BeanUtils.copyProperties(tobSaleInfo, newItem);
                    newItem.setActualInQty(0);
                    newItem.setLeftQty(newItem.getSaleQty() - newItem.getReturnQty());
                    newItem.setMergeKey(mergeKey);
                    newList.add(newItem);
                }
            }
        }
        return newList;
    }

    private List<LogisticsTraceOrderListRkConfirmDetailResponse> t72List(List<LogisticsTraceOrderListRkConfirmDetailResponse> responseList) {
        List<String> mateSkuList = responseList.stream().map(LogisticsTraceOrderListRkConfirmDetailResponse::getMateSku)
                .distinct()
                .collect(Collectors.toList());
        List<String> returnOrderNoList = responseList.stream().map(LogisticsTraceOrderListRkConfirmDetailResponse::getSourceOrderNo)
                .distinct()
                .collect(Collectors.toList());
        List<KeyValueDTO> returnOrderList = mateInventoryOrderQueryMapper.queryT72OrderNo(returnOrderNoList);
        Map<String, String> returnOrderNoMap = returnOrderList.stream()
                .collect(Collectors.toMap(KeyValueDTO::getStringKey, KeyValueDTO::getStringValue));

        List<TobSaleInfo> tobSaleInfoList = mateInventoryOrderQueryMapper.queryT72(returnOrderNoList);
        tobSaleInfoList = tobSaleInfoList.stream()
                .filter(info -> mateSkuList.contains(info.getMateSku())).collect(Collectors.toList());
        List<LogisticsTraceOrderListRkConfirmDetailResponse> newList = new ArrayList<>();
        for (LogisticsTraceOrderListRkConfirmDetailResponse item : responseList) {
            String saleOrderNo = returnOrderNoMap.get(item.getSourceOrderNo());
            String mateSku = item.getMateSku();
            for (TobSaleInfo tobSaleInfo : tobSaleInfoList) {
                if (tobSaleInfo.getSaleOrderNo().equals(saleOrderNo) && tobSaleInfo.getMateSku().equals(mateSku)) {
                    LogisticsTraceOrderListRkConfirmDetailResponse newItem = new LogisticsTraceOrderListRkConfirmDetailResponse();
                    BeanUtils.copyProperties(item, newItem);
                    newItem.setInventoryType(InventoryTypeEnum.ZP.getIntValue());
                    BeanUtils.copyProperties(tobSaleInfo, newItem);
                    newItem.setActualInQty(0);
                    newItem.setLeftQty(newItem.getSaleQty() - newItem.getReturnQty());
                    newList.add(newItem);
                }
            }
        }
        return newList;
    }

    @Operation(summary = "新增")
    @PostMapping("/logisticsTraceOrder/add")
    public CommonResponse<LogisticsTraceOrderAddResponse> addLogisticsTraceOrder(@RequestBody @Validated LogisticsTraceOrderAddRequest request) {
        request.setCreateUserCode(SPRequestContextHolder.getCurrentSystemUserLoginName());
        request.setCreateUserName(SPRequestContextHolder.getCurrentSystemUserRealName());

        List<Long> applyIds = request.getItems().stream().map(LogisticsTraceOrderAddRequest.LogisticsTraceOrderAddRequestMateItem::getId).collect(Collectors.toList());
        this.logisticsTraceOrderMateItemChecking(applyIds);

        return succeedWith(logisticsTraceOrderFacade.addLogisticsTraceOrder(request));
    }

    @Operation(summary = "更新")
    @PutMapping("/logisticsTraceOrder/update")
    public CommonResponse updateLogisticsTraceOrder(@RequestBody @Validated LogisticsTraceOrderUpdateRequest request) {
        List<Long> applyIds = request.getItems().stream().map(LogisticsTraceOrderUpdateRequest.LogisticsTraceOrderUpdateRequestMateItem::getId).collect(Collectors.toList());
        this.logisticsTraceOrderMateItemChecking(applyIds);

        logisticsTraceOrderFacade.updateLogisticsTraceOrder(request);
        return succeed();
    }

    @Operation(summary = "更新流程")
    @PutMapping("/logisticsTraceOrder/updateStep")
    public CommonResponse updateLogisticsTraceOrderStep(@RequestBody @Validated LogisticsTraceOrderUpdateStepRequest request) {
        LogisticsTraceOrderUpdateStepResponse response = logisticsTraceOrderFacade.updateLogisticsTraceOrderStep(request);
        // 上游业务单据状态变更
        if (CollectionUtils.isNotEmpty(response.getSourceOrderNos())) {
            if (response.getSourceOrderType().equals(SubjectEnum.T11.getCode())) {
                //比对入库和采购数量对比
                LogisticsTraceOrderTypeOrderListRequest logisticsRequest = new LogisticsTraceOrderTypeOrderListRequest();
                logisticsRequest.setSourceOrderType(SubjectEnum.T11.getCode());
                logisticsRequest.setSourceOrderNoList(response.getSourceOrderNos());
                List<LogisticsTraceOrderNoOrderDetailResponse> purchaseResp
                        = logisticsTraceApplyOrderFacade.listLogisticsTraceOrderNoOrderDetail(logisticsRequest);
                List<PurchaseOrderNoAndQtyModel> qtyModels = purchaseOrderFacade.queryPurchaseQty(response.getSourceOrderNos());
                Map<String, Integer> qtyMap = purchaseResp.stream()
                        .collect(Collectors.groupingBy(LogisticsTraceOrderNoOrderDetailResponse::getSourceOrderNo
                                , Collectors.summingInt(LogisticsTraceOrderNoOrderDetailResponse::getTraceQty)));
                List<String> orderNoList = new ArrayList<>();
                for (PurchaseOrderNoAndQtyModel qtyModel : qtyModels) {
                    if (qtyModel.getQty().equals(qtyMap.get(qtyModel.getOrderNo()))) {
                        orderNoList.add(qtyModel.getOrderNo());
                    }
                }
                orderServiceStatusFacade.purchaseOrderStatusFinish(orderNoList);
            } else if (response.getSourceOrderType().equals(SubjectEnum.T12.getCode())) {
                orderServiceStatusFacade.purchaseReturnOrderStatusFinish(response.getSourceOrderNos());
            } else if (response.getSourceOrderType().equals(SubjectEnum.T32.getCode())) {
                logisticsTransferOrderFacade.updateLogisticsTransferOrderStatus(response.getSourceOrderNos());
            } else if (response.getSourceOrderType().equals(SubjectEnum.T71.getCode())) {
                orderServiceStatusFacade.saleReturnOrderStatusFinish(response.getSourceOrderNos());
            } else if (response.getSourceOrderType().equals(SubjectEnum.T72.getCode())) {
                orderServiceStatusFacade.saleOrderStatusFinish(response.getSourceOrderNos());
            } else if (response.getSourceOrderType().equals(SubjectEnum.T41.getCode())) {
                orderServiceStatusFacade.tobSaleReturnOrderStatusFinish(response.getSourceOrderNos());
            } else if (response.getSourceOrderType().equals(SubjectEnum.T42.getCode())) {
                orderServiceStatusFacade.tobSaleOrderStatus(response.getSourceOrderNos());
            }
        }
        return succeed();
    }

    @Operation(summary = "返回上一步")
    @PutMapping("/logisticsTraceOrder/backPreviousStep")
    public CommonResponse backLogisticsTraceOrderPreviousStep(@RequestBody @Validated LogisticsTraceOrderBackPreviousStepRequest request) {
        logisticsTraceOrderFacade.backLogisticsTraceOrderPreviousStep(request);
        return succeed();
    }

    @Operation(summary = "删除")
    @PutMapping("/logisticsTraceOrder/delete/{logisticsTraceOrderId}")
    public CommonResponse deleteLogisticsTraceOrder(@PathVariable("logisticsTraceOrderId") Long logisticsTraceOrderId) {
        logisticsTraceOrderFacade.deleteLogisticsTraceOrder(logisticsTraceOrderId);
        return succeed();
    }

    @Operation(summary = "OA提交")
    @PutMapping("/logisticsTraceOrder/oaSubmit")
    public CommonResponse submitLogisticsTraceOrderOA(@RequestBody @Validated LogisticsTraceOrderOaSubmitRequest request) {
        logisticsTraceOrderFacade.submitLogisticsTraceOrderOA(request);
        return succeed();
    }

    @Operation(summary = "OA审核通过")
    @PutMapping("/logisticsTraceOrder/oaApproved")
    public CommonResponse approvedLogisticsTraceOrderOA(@RequestBody @Validated LogisticsTraceOrderOaApprovedRequest request) {
        logisticsTraceOrderFacade.approvedLogisticsTraceOrderOA(request);
        return succeed();
    }

    @Operation(summary = "查询所有流程节点")
    @GetMapping("/logisticsTraceOrder/getLogisticsStepList")
    public CommonResponse<List<LogisticsStepInfo>> getLogisticsStepList(@RequestBody LogisticsStepListGetRequest request) {
        return succeedWith(logisticsTraceOrderFacade.getLogisticsStepList(request));
    }


    private void logisticsTraceOrderMateItemChecking(List<Long> applyIds) {
        LogisticsTraceApplyOrderListRequest applyOrderListRequest = new LogisticsTraceApplyOrderListRequest();
        applyOrderListRequest.setIdList(applyIds);
        List<LogisticsTraceApplyOrderQueryResponse> applyOrderList = logisticsTraceApplyOrderFacade.listLogisticsTraceApplyOrder(applyOrderListRequest);

        String sourceOrderType = "";
        int i = 0;
        for (LogisticsTraceApplyOrderQueryResponse applyOrder : applyOrderList) {
            if (i == 0) {
                sourceOrderType = applyOrder.getSourceOrderType();
            } else {
                if (!applyOrder.getSourceOrderType().equals(sourceOrderType)) {
                    throw new BusinessException(CommonRespCode.PARAM_ERR, "商品明细原始订单类型不一致！");
                }
            }
            i++;
        }

        List<String> applySourceOrderNos = applyOrderList.stream().map(LogisticsTraceApplyOrderQueryResponse::getSourceOrderNo).distinct().collect(Collectors.toList());
        List<String> applySourceDetailOrderNos = applyOrderList.stream().map(LogisticsTraceApplyOrderQueryResponse::getSourceDetailOrderNo).collect(Collectors.toList());
        List<String> businessDetailOrderNos = new ArrayList<>();
        if (sourceOrderType.equals(SubjectEnum.T12.getCode())) {
            businessDetailOrderNos = purchaseReturnOrderFacade.queryPurchaseReturnDetailOrderNosByOrderNos(applySourceOrderNos);
        } else if (sourceOrderType.equals(SubjectEnum.T32.getCode())) {
            businessDetailOrderNos = logisticsTransferOrderFacade.queryLogisticsTransferDetailOrderNosByOrderNos(applySourceOrderNos);
        } else if (sourceOrderType.equals(SubjectEnum.T71.getCode())) {
            businessDetailOrderNos = saleReturnOrderFacade.querySaleReturnDetailOrderNoByOrderNo(applySourceOrderNos);
        } else if (sourceOrderType.equals(SubjectEnum.T72.getCode())) {
            businessDetailOrderNos = saleOrderFacade.querySaleOrderDetailOrderNoByOrderNo(applySourceOrderNos);
        } else if (sourceOrderType.equals(SubjectEnum.T41.getCode())) {
            businessDetailOrderNos = tobSaleReturnOrderFacade.queryTobSaleReturnOrderDetailOrderNosByOrderNos(applySourceOrderNos);
        } else if (sourceOrderType.equals(SubjectEnum.T42.getCode())) {
            businessDetailOrderNos = tobSaleOrderFacade.queryDetailOrderNoByOrderNo(applySourceOrderNos);
        }

        if (
                businessDetailOrderNos.size() > 0 && (
                        businessDetailOrderNos.size() != applySourceDetailOrderNos.size() ||
                                !businessDetailOrderNos.containsAll(applySourceDetailOrderNos) ||
                                !applySourceDetailOrderNos.containsAll(businessDetailOrderNos)
                )
        ) {
            throw new BusinessException(CommonRespCode.PARAM_ERR, "勾选订单不完整！");
        }
    }

}